Skip to content

feat(agent,agent-installer): add transactional policy store - #1963

Open
Benoît Cortier (CBenoit) wants to merge 31 commits into
cbenoit-plan-agent-policy-endpointfrom
cbenoit-phase-2-policy-store
Open

feat(agent,agent-installer): add transactional policy store#1963
Benoît Cortier (CBenoit) wants to merge 31 commits into
cbenoit-plan-agent-policy-endpointfrom
cbenoit-phase-2-policy-store

Conversation

@CBenoit

@CBenoit Benoît Cortier (CBenoit) commented Aug 29, 2026

Copy link
Copy Markdown
Member

Adds authenticated transactional package-policy management to Devolutions Agent, including deterministic validation, optimistic concurrency, crash-safe JSON persistence, secure path and ACL enforcement, and stable old-or-new runtime snapshots.

Policy writes require the actual named-pipe client token to be elevated with the Administrators group enabled. Read, management, and validation remain available to an authenticated standard user. Structured tracing, Windows Event Log auditing, fail-closed watcher reconciliation, and split unelevated/LocalSystem end-to-end coverage make policy changes observable and recoverable.

Caller authentication binds a retained executable candidate to the process main-image section with NtQueryInformationProcess(ProcessImageFileMapping), rejects network/provider image paths, verifies Devolutions Authenticode through the retained handle, and permits only trusted writers to tamper with the executable or its pinned, reparse-safe ancestor path. The same-stream regression proves that class 44 and a current valid signature are insufficient alone: a user-writable rewritten stream is rejected by the retained file and ancestor security policy.

This authenticates approved image and file provenance at connection time, not runtime memory integrity or historical bytes. Same-integrity injection or hollowing of an approved non-PPL process is outside signed-image authentication. Such control grants no additional read, management, or validation authority beyond running signed UniGetUI, and a standard or medium-integrity user still cannot replace policy because the pipe token must independently be elevated and Administrators-enabled. SYSTEM and elevated-Administrator injection are inside the write trust boundary; stronger runtime integrity requires an appropriate WDAC policy or compatible PPL protection levels.

Current ACL verification cannot reconstruct historical write access. Trust assumes the approved binary and each ancestor were secure when created and were never untrusted-writable. Operators must reinstall or remediate after any ACL or path compromise before trusting the deployment again; installer and package verification establish secure deployment, while runtime checks fail closed on present insecurity.

Non-Create replacement retains the exact token-observed file and directory path, writes a durable secure transaction marker and replacement, moves the observed target to a tombstone by handle, and publishes the replacement by a no-replace handle-relative rename. Concurrent external content is never overwritten. Startup recovery restores the exact verified tombstone when the final leaf is absent, preserves any raced-in or published final leaf, and fails closed on malformed, ambiguous, or insecure remnants.

The default policy tree is traversed under retained no-delete-share handles from ProgramData. Existing shared Devolutions directories may retain compatible create-only sibling grants, but path-tampering grants are rejected; the dedicated PackageBroker directory always requires strict SYSTEM/Administrators-only security. Missing components receive protected security at creation, and race winners are reopened without following reparses and verified before traversal continues.

The store preserves structured API failures, binds ConfirmOverwrite to the exact observed store token, restricts committed revisions and rule priorities to 1..=2,147,483,647 where applicable, and migrates eligible legacy policy files transactionally. Migration commit and rollback retain verified marker handles through deletion so path replacement or in-place marker rewrites cannot delete newer content.

Uses official crates.io releases now-policy 0.3.0, now-policy-api 0.4.0, and now-policy-server-template 0.4.0 with no now-libraries git source. Committed documents use https://devolutions.net/schemas/now-policy.schema.1.0.json; editable drafts use https://devolutions.net/schemas/now-policy-draft.schema.1.0.json.

Local validation includes Rust formatting, locked default and development broker suites, warnings-denied workspace Clippy, the full locked workspace suite, the i686 Windows broker check, Agent and policy-tester builds, the unelevated Agent policy end-to-end suite, direct Win32/native handle-relative rename tests, transaction crash/race recovery tests, and hostile directory creation tests. Exact-head CI provides the LocalSystem Repair and full end-to-end legs.

Stacked on #1937.
Shared contract: Devolutions/now-libraries#99 with the corrective follow-up in Devolutions/now-libraries#101.
Registry publication: Devolutions/now-libraries#98.

@CBenoit

Copy link
Copy Markdown
Member Author

Implementation notes:

  • Replaces the watcher-owned policy mutation path with one serialized PolicyStore that publishes immutable Active/Missing/Invalid snapshots.
  • Uses the exact ec592a91f95a66c8a79b7d612ed73d931ef74aeb now-libraries contract, keyed validation receipts, opaque disk-state tokens, and explicit Create/Update/Repair/ReplaceIdentity semantics.
  • Restricts writable policy storage to securely resolved JSON paths with SYSTEM/Administrators-only protection, same-directory atomic publication, post-write verification, and synchronous post-publication reconciliation.
  • Requires the existing caller-signature validation plus actual elevation and enabled Administrators membership for writes; the development signature bypass does not bypass authorization.
  • Audits attempts and outcomes through structured tracing and the Agent Windows Event Log without policy content.
  • Validation completed: diff check and rustfmt; 409 default and 413 dev-skip broker tests passed except the existing host-specific Winget AppExecAlias DACL baseline; sysevent-codes (1), sysevent-winevent (8), and win-api-wrappers (25) tests passed; workspace check and Clippy with warnings denied passed; Agent debug and release message-resource builds passed; unelevated Agent policy E2E passed. LocalSystem E2E is wired into Windows CI but could not run in this medium-integrity shell because PsExec could not install PSEXESVC.

Note

Human-tuned, LLM-assisted content.

@CBenoit

Copy link
Copy Markdown
Member Author

CI repair update (be3a9edf):

  • Resolves the verified policy parent through its held handle before comparing the leaf, so 8.3 parent aliases and case-only leaf differences are accepted without weakening location checks.
  • Rejects policy files with multiple hard links using FILE_STANDARD_INFO.NumberOfLinks instead of relying on which link name GetFinalPathNameByHandleW reports.
  • Runs the unelevated E2E suite through PsExec -l; the tester now fails immediately unless its token is both non-elevated and lacks enabled Administrators membership. LocalSystem remains a separate mode.
  • Selects and validates one deterministic mc.exe result before exporting WindowsSdkVerBinPath.

Focused validation passed: 37 policy-store Windows tests, 3 token-wrapper tests, agent-policy-tester check, direct unelevated E2E with token assertion, rustfmt, diff check, and targeted Clippy with warnings denied. Workflow assertions for restricted launch and single message-compiler selection also passed; actionlint is not installed locally.

Note

Human-tuned, LLM-assisted content.

@CBenoit

Copy link
Copy Markdown
Member Author

Follow-up CI repair (9c85810a): the restricted PsExec process could not create its transcript in the protected checkout. The wrapper now uses the user's low-integrity LocalLow\Temp directory for test artifacts and streams stdout/stderr back through the parent CI process, preserving the explicit non-elevated/non-admin token assertion and expected 403 behavior.

Local script parsing, workflow assertions, diff/rustfmt, agent-policy-tester check, and targeted Clippy passed.

Note

Human-tuned, LLM-assisted content.

@CBenoit

Copy link
Copy Markdown
Member Author

Final CI status: run 33254105745 passed at c1b72fe33b36dc1d80d79ee6d8d759d76ef9e275, including the restricted unelevated and LocalSystem Agent policy E2E modes, Windows path/hardlink tests, and Agent release message-resource build. The worktree is clean and the pushed upstream SHA matches locally.

Note

Human-tuned, LLM-assisted content.

@CBenoit

Copy link
Copy Markdown
Member Author

Shared-contract refresh provenance for 78f7c6bbb399f146245c7f693221786110e647d7 (2026.8.29-phase2.78f7c6bb):

  • OpenAPI SHA-256: 759481ac915fb0d48a602f90ad037261d5045c9a3ae906d293fef7ff3c74d469
  • Policy schema SHA-256: cd156264ed107890e0eeb9046d19fe0caf9bbc3f270235d434533bb325626fe8
  • API nupkg: c0d25dd367bba2e119a62987cc45fdfe61bd3837096d5872554b9d0c943fecac
  • API snupkg: c2b20126ffd8d63713b844f38cf920e356c5547d87306d1786aa8bd2fe800ab1
  • Client nupkg: 9bd84dc16ac05bb97ff579d48f6be55c70ed83a71cc021586deae6d32a945e34
  • Client snupkg: cab11a1cc045f26c0e79bf3733cf64f093fc771e2297e2e35c12f91489a9a972
  • Model nupkg: 0c3eb06d14bcc9fcd3374fb87a18e7bf56faa54d5978a9552897d299c1d6e04d
  • Model snupkg: 18a0088876e4f5968b59d7d9502046e281d508bfc8e3af5ade2731a7cf2d75be

All six local artifacts were rehashed and matched provenance.json. They remain unpublished. The reviewed shared delta changes direct .NET DTO invariant enforcement and diagnostic wording only; Rust signatures, OpenAPI, and policy schema are unchanged, so Gateway required only the exact three-crate revision/lock refresh.

Local validation: rustfmt and diff checks passed; locked broker suites passed 409/413 tests respectively with only the documented host Winget AppExecAlias DACL baseline; locked targeted check and Clippy with warnings denied passed; Agent and tester builds passed; unelevated Agent policy E2E passed.

Note

Human-tuned, LLM-assisted content.

@CBenoit

Copy link
Copy Markdown
Member Author

Authoritative shared-contract refresh at 44210762f7eb3a947d322e8732d6ae7c86941154 (2026.8.29-phase2.44210762):

  • OpenAPI SHA-256: 759481ac915fb0d48a602f90ad037261d5045c9a3ae906d293fef7ff3c74d469
  • Policy schema SHA-256: cd156264ed107890e0eeb9046d19fe0caf9bbc3f270235d434533bb325626fe8
  • API nupkg: 8058bc671bc286db7f165b3dea6b49c09c7fbe167cf9b2ea423aec477fd5384e
  • API snupkg: 9dadb0385b1becd57166266296d495d4f844b36510401af2ab878c4c3fd1eeb1
  • Client nupkg: af38db5b2fc77763d696a8f94e2c79bd29ba1d7fe3baee16ae8650cbbccd4be1
  • Client snupkg: 623ab2d87361002f2f340096bf156dd2aecec67a7193f9df74b83167ca14fd24
  • Model nupkg: 014a27ea541b662dd3f2b8323481e399b7569a317d9923a90fcb12ff1ed6162e
  • Model snupkg: f7d7779c647aa9cbd6dd1208c337e7583b218f7fb1c8f7ab31c1c3c831ebfe8f

All six unpublished artifacts were rehashed and match provenance.json. Wire formats, DTOs, OpenAPI, and policy schema are unchanged. Gateway now uses the reviewed explicit PolicyDocument::to_draft() projection and pins all three Rust policy crates and lock sources to the exact head.

Local validation: rustfmt and diff checks passed; locked broker suites passed 409/413 tests respectively with only the documented host Winget AppExecAlias DACL baseline; locked targeted check and Clippy with warnings denied passed; Agent and tester builds passed; unelevated Agent policy E2E passed. Exact-head CI: 33764438462.

Note

Human-tuned, LLM-assisted content.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved upgrade, filesystem-concurrency, authorization, and installer-security issues undermine the transactional guarantees.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds authenticated transactional JSON policy management to Devolutions Agent, including secure persistence, validation, auditing, and end-to-end coverage.

Changes:

  • Replaces the legacy loader/watcher with a transactional policy store.
  • Adds elevation, ACL, concurrency-token, and Windows Event Log protections.
  • Expands Windows CI and privileged/unelevated testing.
File summaries
File Description
.github/workflows/ci.yml Adds SDK discovery and policy test modes.
Cargo.lock Locks new contract and security dependencies.
Cargo.toml Pins Phase 2 policy crates.
crates/agent-policy-tester/Cargo.toml Adds Windows policy-test dependencies.
crates/agent-policy-tester/run-as-system.ps1 Selects elevated test mode.
crates/agent-policy-tester/run-unelevated.ps1 Adds restricted-token test runner.
crates/agent-policy-tester/src/windows.rs Tests management lifecycle and authorization.
crates/now-package-broker/Cargo.toml Adds receipts and audit dependencies.
crates/now-package-broker/src/audit.rs Implements structured policy auditing.
crates/now-package-broker/src/auth.rs Captures elevation and administrator membership.
crates/now-package-broker/src/evaluator/mod.rs Exposes wildcard validation internally.
crates/now-package-broker/src/evaluator/wildcard.rs Shares wildcard compilation checks.
crates/now-package-broker/src/lib.rs Registers policy-store modules.
crates/now-package-broker/src/policy_loader.rs Removes the legacy loader.
crates/now-package-broker/src/policy_security.rs Strengthens policy filesystem security.
crates/now-package-broker/src/policy_store/mod.rs Implements transactional store coordination.
crates/now-package-broker/src/policy_store/receipt.rs Adds keyed validation receipts.
crates/now-package-broker/src/policy_store/validation.rs Implements deterministic policy validation.
crates/now-package-broker/src/policy_store/windows.rs Implements secure Windows persistence.
crates/now-package-broker/src/policy_watcher.rs Removes the legacy watcher.
crates/now-package-broker/src/scenario_tests.rs Makes scenarios JSON-only.
crates/now-package-broker/src/server/mod.rs Adds policy-management routes and authorization.
crates/now-package-broker/src/server/responses.rs Maps management errors and snapshots.
crates/now-package-broker/src/task.rs Integrates the transactional store.
crates/now-package-broker/src/test_support.rs Adds shared SID test support.
crates/sysevent-codes/src/lib.rs Defines policy audit events.
crates/sysevent-codes/tests/message_catalog_parity.rs Checks event-catalog parity.
crates/sysevent-winevent/src/lib.rs Corrects null-handle detection.
crates/win-api-wrappers/src/token.rs Adds token group-membership checks.
devolutions-agent/build.rs Embeds the Agent message catalog.
devolutions-agent/devolutions-agent.mc Adds the Agent event catalog.
devolutions-gateway/devolutions-gateway.mc Mirrors policy audit messages.
package/AgentWindowsManaged/Actions/AgentActions.cs Schedules policy-directory actions.
package/AgentWindowsManaged/Actions/CustomActions.cs Creates and secures the policy directory.
package/AgentWindowsManaged/Program.cs Registers the Agent event source.
package/AgentWindowsManaged/Resources/Includes.cs Defines the policy-directory SDDL.
Review details
  • Files reviewed: 34/36 changed files
  • Comments generated: 10
  • Review effort level: Balanced

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread crates/now-package-broker/src/auth.rs Outdated
Comment thread crates/now-package-broker/src/policy_store/windows.rs
Comment thread crates/now-package-broker/src/policy_store/windows.rs Outdated
Comment thread Cargo.toml Outdated
Comment thread crates/now-package-broker/src/policy_store/mod.rs
Comment thread crates/now-package-broker/src/task.rs
Comment thread devolutions-agent/build.rs Outdated
Comment thread package/AgentWindowsManaged/Actions/AgentActions.cs Outdated
Comment thread package/AgentWindowsManaged/Actions/CustomActions.cs Outdated
Comment thread crates/sysevent-codes/tests/message_catalog_parity.rs Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Migration cleanup uses an incorrect Win32 field ABI, and the dependency-publication gate remains unresolved.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 38/40 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread package/AgentWindowsManaged/Actions/WinAPI.cs Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Production resource embedding and legacy ACL migration are defective, and registry dependency publication remains incomplete.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

devolutions-agent/build.rs:128

  • Master builds and packages the Agent with the custom production profile (.github/workflows/ci.yml:135-144, 1011, 1036), but this gate embeds the message catalog only when PROFILE is literally release. The shipped production binary will therefore lack the message-table resource that the installer registers as EventMessageFile, so Event Viewer cannot format these audit events. Include the production profile in this gate (or detect release-like profiles without relying on the profile name).
  • Files reviewed: 38/40 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread package/AgentWindowsManaged/Actions/CustomActions.cs Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Boolean constraint validation is incorrect, and published registry dependencies remain an explicit merge gate.

Review details

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

crates/now-package-broker/src/policy_store/validation.rs:699

  • This rejects a rule whenever the match set contains true, even when it also contains false. The evaluator treats {true, false} as matching either value (bool_in_set), so with AllowInteractive: false that rule can still match requests where Interactive is false and is not contradictory. Require the set to contain only true before reporting it as unreachable.
    crates/sysevent-codes/src/lib.rs:389
  • Event 8000 is emitted before validate_connection and the elevation/Administrators check in server/mod.rs, so unauthenticated and unelevated requests also produce it. Describing every actor as an authenticated elevated Administrator makes the audit event's documented meaning inaccurate.
  • Files reviewed: 38/40 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Two validation paths mishandle reachable rules, and the temporary contract dependency pins remain an explicit merge gate.

Review details

Suppressed comments (2)

Previously missed (1) — in code that hasn't changed since the last review.

crates/now-package-broker/src/policy_store/validation.rs:641

  • Validation accepts non-empty PackageNames, but the evaluator deliberately returns false for every such rule because package requests contain no display name (evaluator/matching.rs:25,255-259). This silently accepts an allow rule that can never apply, contrary to this validator's strict ineffective-match checks. Reject this criterion until the request contract exposes a value that can be matched.

This issue also appears on line 698 of the same file.

crates/now-package-broker/src/policy_store/validation.rs:698

  • This also flags [false, true] as contradictory merely because the set contains true. The evaluator still permits requests whose actual value is false, and the constraint only rejects actual true values, so that rule remains reachable. Require the match set to be exactly {true} before reporting this finding.
    let mut check = |bool_match: &BTreeSet<bool>, allow_flag: bool, option_name: &str| {
  • Files reviewed: 38/40 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@CBenoit

Copy link
Copy Markdown
Member Author

Parent disposition for review 5106045608 is implemented in 58ea2509.

  • Non-empty PackageNames criteria now fail authoritative validation with InvalidFieldValue, the exact /Rules/{i}/Match/PackageNames pointer, the rule ID, and a deterministic unsupported-criterion message. Empty PackageNames remains valid when another effective criterion is present. Wildcard validation no longer emits duplicate findings for this unsupported criterion.
  • Boolean contradiction detection now requires the match set to be exactly {true}. {false} remains reachable, helper-level {false, true} is not mislabeled as contradictory, and end-to-end mixed sets remain rejected by the shared strict cardinality contract.
  • Validator receipts were rotated to now-package-broker-policy-validator/2 because the authoritative semantics changed.

All 54 validator tests and the full broker run passed (428 passed, 1 ignored, 1 filtered), followed by warnings-denied targeted Clippy and git diff --check. The temporary dependency-pin publication gate remains intentionally unresolved and must be repinned to compatible published registry versions before merge.

Note

Human-tuned, LLM-assisted content.

@CBenoit

Copy link
Copy Markdown
Member Author

Parent disposition for the Event 8000 concern in review 5105977874 is implemented in 66dde174.

Event 8000 remains intentionally emitted before signature, elevation, and Administrators checks so denied write attempts are present in the audit trail. Its public contract now describes an attempted policy write by the OS-identified connected pipe client before final authorization; it no longer claims the actor is already authenticated or privileged. The authorization audit sequence is explicit and a focused regression proves both failed-authentication and unelevated paths emit Attempted followed by Denied, without implying successful authorization.

The focused audit regression, message-catalog parity test, full broker run (428 passed, 1 ignored, 1 filtered), warnings-denied Clippy, and git diff --check passed.

Note

Human-tuned, LLM-assisted content.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Handle-bound authentication, rollback cleanup, Unicode path comparison, and dependency publication issues remain unresolved.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (3)

Previously missed (3) — in code that hasn't changed since the last review.

crates/now-package-broker/src/policy_security.rs:756

  • This claims Windows case-insensitive comparison but only folds ASCII. Windows paths may contain non-ASCII characters and use ordinal Unicode case mapping, so a valid configured ancestor whose stored casing differs (for example, accented letters) is rejected as an unexpected location. Use Windows ordinal case-insensitive UTF-16 comparison, such as CompareStringOrdinal(..., TRUE), rather than eq_ignore_ascii_case.
    crates/now-package-broker/src/policy_store/windows.rs:668
  • This second Windows path comparator is also ASCII-only. As a result, a policy leaf with non-ASCII casing that Windows resolves successfully can be classified as a retargeted/unsafe file and made read-only. Reuse a Windows ordinal case-insensitive UTF-16 comparison helper here instead of eq_ignore_ascii_case.
    package/AgentWindowsManaged/Actions/CustomActions.cs:1953
  • This releases the validated marker handle and then deletes whatever currently occupies marker by path. A replacement marker created in that gap is therefore deleted without the identity/content binding promised by the migration cleanup. Open the marker with DELETE access and call DeleteFileByHandle(markerPath.Leaf) before leaving the using block, as the commit action already does.
  • Files reviewed: 38/40 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread crates/now-package-broker/src/auth.rs Outdated
@CBenoit

Copy link
Copy Markdown
Member Author

Review 5106288221 and the related suppressed findings are addressed on exact head 5183ac03926a22186c41ecf3df716b196db12db7.

  • Authenticode validation now binds embedded signatures, catalog hashing, catalog member verification, and the live SHA-256 catalog context to the exact retained client executable handle. The inline thread is resolved with focused junction-retarget and crypt-test evidence.
  • Both policy path comparisons now reuse CompareStringOrdinal(..., TRUE) over UTF-16. Accented non-ASCII casing is accepted, while unequal parent and leaf paths remain rejected.
  • Rollback marker owner/DACL inspection, JSON parsing, and deletion now use the same retained READ+DELETE handle. A focused probe proved a path reopen sharing-fails while the marker remains parseable and the exact pinned destination and marker are deleted.
  • Event 8000 remains intentionally pre-authorization so denied attempts are audited; its contract no longer claims successful authentication/elevation, and focused tests prove Attempted precedes Denied for failed-authentication and unelevated clients.
  • The legacy ACL thread remains resolved with Users-read accepted and inherited LOCAL SERVICE-write safely skipped without content promotion.
  • Non-empty PackageNames is rejected with deterministic rule ID/exact-pointer evidence, and boolean contradictions require exact singleton {true} while mixed cardinality remains structurally rejected.

Full validation passed: 430 broker tests (1 ignored, 1 documented host-specific filter), 29 Windows-wrapper tests, 26 Agent-shared tests, message-catalog parity, targeted warnings-denied Clippy, managed-installer Compile, and git diff --check. Dependency publication is still incomplete; the registry-repin thread remains the sole unresolved merge gate.

Note

Human-tuned, LLM-assisted content.

@CBenoit
Benoît Cortier (CBenoit) requested a balanced review from Copilot September 3, 2026 20:55
Replace the temporary now-libraries git patches with the official registry releases from Devolutions/now-libraries#99.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Bind named-pipe clients to the process image section and retain verified executable and ancestor handles for Authenticode and ACL checks.

Bound unauthenticated capture work and cover same-stream rewriting without claiming runtime or historical integrity.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep the verified marker handle open with delete access from parsing through deletion so in-place rewrites cannot preserve identity and escape validation.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Allow the same-stream regression to observe either an untrusted owner or an untrusted write ACE, since both are valid fail-closed outcomes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Retain the token-observed target and publish through a durable handle-based tombstone transaction so concurrent external content is never overwritten and interrupted writes recover deterministically.

Enforce the shared rule-priority maximum and rotate validation receipts with validator version 3.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Carry Phase 1's 404 inspection and 503 evaluation split while removing Phase 1-only assertions that management routes remain hidden after Phase 2 enables them.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep Phase 1's function-level large-error expectations and remove the now-redundant module-level expectation after Phase 2 route integration.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Default-directory creation can follow an attacker-controlled junction before ancestor verification.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 39/42 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread crates/now-package-broker/src/policy_store/windows.rs Outdated
Verify the complete existing ancestor chain before the runtime fallback creates the protected policy directory, preventing privileged side effects through a pre-created junction.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Create transactions lack retained-directory anchoring, and capability-only updates produce false policy-change audits.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

crates/now-package-broker/src/policy_security.rs:861

  • This paragraph describes ancestor verification, but it is attached to final_path_from_handle, which only resolves a path. Remove the stale paragraph so the function's documentation matches its behavior.
  • Files reviewed: 39/42 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread crates/now-package-broker/src/policy_store/mod.rs Outdated
Create default policy components under retained verified parents, permit compatible shared-vendor ACLs while keeping PackageBroker strict, and use tested handle-relative rename transitions.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Create default policy components under retained verified parents, support compatible shared-vendor ACLs, and use tested handle-relative file transitions.

Avoid policy-change audit events for capability-only snapshot updates.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Legacy migration can delete a policy file that remains explicitly configured as the Agent’s active path.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 39/42 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread package/AgentWindowsManaged/Actions/CustomActions.cs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Client-token impersonation occurs before any pipe message is read, causing real connections to fail authentication.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 39/42 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread crates/now-package-broker/src/auth.rs Outdated
Capture authorization from the retained connector process token without premature pipe impersonation, and reject inherited connections after the original process exits.

Preserve an explicitly configured legacy policy during installer migration using strict config parsing and pinned file identity.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The security-critical 15,000-line change requires final human review despite substantial automated coverage.

Review details
  • Files reviewed: 39/42 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@CBenoit
Benoît Cortier (CBenoit) marked this pull request as ready for review September 4, 2026 13:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants